Sissejuhatus

Siin praktikumis jätkame ggplot2 võimaluste õppimisega. Selleks, et tööga pihta saaks hakata, loeme sisse vajalikud paketid ja andmestiku.

library(ggplot2)
library(tidyverse)

load("linnad.RData", verbose = T)
Loading objects:
  linnad

Faktoritega töötamine

Pakett ggplot2 üritab võimalikult palju kasutada joonistamisel informatsiooni mis on kodeeritud faktori tasemetesse. Faktor on andmetüüp diskreetsetele muutujatele, mis säilitab lisaks väärtustele ka info küigi võimalike väärtuste ning nende järjestuste kohta. Faktori taseme nimede põhjal joonistatakse näiteks legend ja taseme järjestust kasutatakse telgedel elementide järjestamiseks. Seetõttu on oluline tunda paari nippi kuidas faktorite tasemetega töötada. 

Esiteks on kasulik panna faktori tasemetele sisukad nimed. Seda saab teha andes käsule factor ette juba sisukate nimedega sõnevektori, kasutades argumenti labels.

a = factor(c(1, 1, 1, 2, 2, 3), labels = c("A", "B", "C"))
a
[1] A A A B B C
Levels: A B C

Faktori tasemete nimesid saab muuta kasutades käsku fct_recode (tuleb kaasa tidyverse paketiga). Sellega saab ka faktori tasemeid kokku võtta.

fct_recode(a, "I" = "A", "II" = "B", "III" = "C")
[1] I   I   I   II  II  III
Levels: I II III
fct_recode(a, "I" = "A", "II" = "B")
[1] I  I  I  II II C 
Levels: I II C
fct_recode(a, "I" = "A", "II" = "B", "I" = "C")
[1] I  I  I  II II I 
Levels: I II

Faktori tasemete järjestust saab muuta ka käsuga fct_relevel, kus etteantud tasemed tõstetakse jäjekorras ette poole

a = factor(c(1, 1, 1, 2, 2, 3), labels = c("A", "B", "C"))
a
[1] A A A B B C
Levels: A B C
fct_relevel(a, "C")
[1] A A A B B C
Levels: C A B
fct_relevel(a, "C", "B", "A")
[1] A A A B B C
Levels: C B A

Kui me tahame muuta faktorite järjekorda mingi teise vektori järgi, siis saab kasutada käsku fct_reorder.

a = factor(c(1, 1, 1, 2, 2, 3), labels = c("A", "B", "C"))
b = c(1, 5, 6, 2, -4, 10)
a
[1] A A A B B C
Levels: A B C
b
[1]  1  5  6  2 -4 10
fct_reorder(a, b)
[1] A A A B B C
Levels: B A C
fct_reorder(a, b, .desc = T)
[1] A A A B B C
Levels: C A B
fct_reorder(a, b, .fun = max)
[1] A A A B B C
Levels: B A C

Seega kui me tahame mugandada pilti on tihtipeale kasulikum enne mugandada andmeid ja siis nendega pilt joonistada.

ggplot(linnad, aes(x = per_capita_inc, y = unemployment_rate, colour = income_class)) +
  geom_point() 


linnad %>% 
  mutate(income_class = fct_recode(income_class, "High" = "Very High", "Low" = "Very Low", "Low" = "Medium")) %>% 
  ggplot(aes(x = per_capita_inc, y = unemployment_rate, colour = income_class)) +
    geom_point() 

ggplot(linnad, aes(x = per_capita_inc, y = unemployment_rate, colour = Poverty_factor)) +
  geom_point() 


linnad %>% 
  mutate(Poverty_factor = fct_relevel(Poverty_factor, "Low", "Medium", "High")) %>% 
  ggplot(aes(x = per_capita_inc, y = unemployment_rate, colour = Poverty_factor)) +
  geom_point() 

ggplot(linnad, aes(x = County, y = pop_estimate)) +
  geom_bar(stat = "identity") 


linnad %>% 
  mutate(County = fct_reorder(County, pop_estimate)) %>% 
  ggplot(aes(x = County, y = pop_estimate)) +
    geom_bar(stat = "identity") 

Ülesanded

  • Joonistage seos bachelor ja high_scl vahel ning näidake värviga tunnust income_class . Võta koku klassid “Very Low” ja “Low” ning uuda värvide järjekord nii, et see algaks väga kõrgest ja lõppeks madalaga.

linnad %>% 
  mutate(income_class = fct_recode(income_class, "Low" = "Very Low")) %>%
  mutate(income_class = fct_relevel(income_class, "Low", "Medium", "High", "Very High" )) %>% 
  ggplot(aes(x = bachelor , y = high_scl , colour = income_class )) +
  geom_point() 

Graafikute annoteerimine ja mugandamine

Graafikute annoteerimine

Telgede ja graafiku annoteerimise viise me oleme juba töö käigus näinud. Paljud asjad saab ära lahendada erinevate skaleerimisfunktsioonide parameetritega. Siiski on paljudele neis olemas ka mugavamad vasted eraldi funktsioonidega mis hoiavad trükkimist kokku. Neist olulisemad on 

  • ggtitle() - määrame graafiku pealkirja

  • xlab(), ylab() - telgede pealkirjad

  • xlim(), ylim() - telgede väärtusvahemiku määramine

Graafikute stiil

Vahest on vaja muuta ggplot2 graafikute üleüldist stiili või mõne elemendi väljanägemist. Näiteks on standardne ggplot2 graafikute taust hall, mis ei ole alati parim lahendus. Seda on lihtne muuta käsuga theme_bw mis teeb tausta valgeks ja muudab ka portsu muude graafiku elementide värve ja kuju.

ggplot(linnad, aes(x = per_capita_inc, y = unemployment_rate, colour = birth_class)) +
  geom_point() +
  theme_bw() 

Neid funktsioone on veel, tasub vaadata mida RStudio pakub, kui kirjutada algus theme_ . Veel rohkem erinevaid teemasid on olemas paketis ggthemes (https://yutannihilation.github.io/allYourFigureAreBelongToUs/ggthemes/).

library(ggthemes)
ggplot(linnad, aes(x = per_capita_inc, y = unemployment_rate, colour = birth_class)) +
  geom_point() +
  theme_wsj() 

Täpsemalt saab muuta konkreetseid elemente käsuga theme. Siin on terve ports parameetreid mis töötavad hierarhiliselt. Olulisemad on toodud järgmisel joonisel.

Nendele saabväärtuseks anda käske element_text, element_line ja element_rect vastavalt parameetri tüübile. Käskude element_* parameetrid vastavad suhteliselt täpselt sarnaste elementide grid paketis kasutatavatele parameetritele. Oluline funktsioon on ka element_blank mis vastava elemendi lihtsalt ära kustutab.

ggplot(linnad, aes(x = per_capita_inc, y = unemployment_rate, colour = birth_class)) +
  geom_point() +
  theme(panel.background = element_rect(fill = "pink"), panel.grid.minor = element_blank())

Väga oluline parameeter käsus theme on ka legend.position. Kui selle väärtuseks on "none" kustutatakse legend ära. Väärtused "left", "right", "top" ja "bottom" käituvad nagu võiks oodata . Andes ette kahe elemendilise vektori paigutab ta legendi graafiku ala sees vastavalt antud koordinaatidele, paralleelselt on hea kasutada ka legend.justification argumenti, mis võimaldab legendi paigutust täpsemalt kontollida.

ggplot(linnad, aes(x = per_capita_inc, y = unemployment_rate, colour = birth_class)) +
  geom_point() +
  theme(legend.position = "none")
ggplot(linnad, aes(x = per_capita_inc, y = unemployment_rate, colour = birth_class)) +
  geom_point() +
  theme(legend.position = "bottom")
ggplot(linnad, aes(x = per_capita_inc, y = unemployment_rate, colour = birth_class)) +
  geom_point() +
  theme(legend.position = c(1,1), legend.justification = c(1, 1))

Ülesanded

  • Proovi saavutada umbes järgmine pilt.

ggplot(linnad, aes(x = bachelor, y = high_scl, colour = income_class)) +
  geom_point() +
  scale_color_brewer(type="div", palette=2) +
  ggtitle("High School and Higher Education") +
  theme(
    panel.background = element_rect(fill = "gold"),
    axis.text.x = element_text(angle=45),
    legend.position = c(1,0), 
    legend.justification = c(1, 0),
    legend.background = element_rect(color = "black"),
    legend.key = element_rect(fill = "grey95")
  )

Graafikute salvestamine

Grafikuid saab salvestada käsuga ggsave(), Kui ette anda vaid faili nimi, siis salvestab see käsk viimase graafiku, mis sai joonistatud, kusjuures suuruse võtab ta akna järgi ning failitüübi määrab faili nime laiendi järgi.

Parameetreid width ja height kasutades on võimalik ära määrata ka täpselt joonise mõõdud (tollides).

ggplot(linnad, aes(x = per_capita_inc, y = unemployment_rate, colour = Poverty_factor)) +
  geom_point() +
  theme(legend.position = c(1,1), legend.justification = c(1, 1))

ggsave("plot1.png")
ggsave("plot1.pdf")
ggsave("plot1_wide.png", width = 10, height = 5)

Soovitav on salvestada jooniseid .pdf formaadis. Nii tehakse vektorgraafika ja pilt on alati hea kvaliteediga. Kui soovida (Windowsil), et kas raster kujul salvestatud pildid näiteks .png failid head välja näeksid tasub muuta vaikimisi graafika mootorit RStudios järgnevalt.

Erinevate graafikute kokku panemine

Graafikute tahkudeks jagamine toimib väga hästi, kui me tahame ühte tüüpi graafikut jagada mitmeks. Kuid kui me tahame erinevat tüüpi graafikuid erinevatel muutujatel samal pildil kõrvuti näidata, siis sama lähenemine ei tööta. Siin tulevad appi lisapaketid. Näiteks patchwork on üks mis võimaldab ggplot2 graafikuid kokku panna.

Enne, kui läheme patchwork-i enda juurde vaatame ühte kasulikku nippi. Nimelt on võimalik ggplot graafik muutujana salvetada. Joonistatakse see alles siis kui muutuja väärtus on vaja välja trükkida.

p = ggplot(linnad, aes(x = per_capita_inc, y = unemployment_rate, colour = Poverty_factor)) +
  geom_point()

p
p + theme_bw()

Loeme sisse paketi patchwork ja defineerime kolm graafikut mida kombineerima hakata.

install.packages("patchwork")
library(patchwork)

p1 = ggplot(linnad, aes(x = per_capita_inc)) +
  geom_histogram() +
  ggtitle("Plot 1")
p2 = ggplot(linnad, aes(x = per_capita_inc, y = unemployment_rate, colour = Poverty_factor)) +
  geom_point() +
  ggtitle("Plot 2")
p3 = ggplot(linnad, aes(x = State, y = unemployment_rate, fill = State)) +
  geom_boxplot() +
  ggtitle("Plot 3")


p1
p2
p3

Patchworkis tehakse ka graafikutega “tehteid”. Selleks, et graafikuid kõrvuti panna on tehe |.

p1 | p2  

Üksteise alla saab panna graafikuid tehtega / .

p1/p2

Tehteid saab ka kombineerida, siis tuleb tähelepanu juhtida tehete järjekorrale

p1 | p2 / p3

(p1 | p2) / p3

Selleks, et piltide paigutust paremini kontrollida on funktsioon plot_layout, millega saab joonise erinevaid aspekte muuta. Näiteks heights parameeter võimaldab muuta piltide suhtelisi kõrguseid.

p1 / p2 / p3 + plot_layout(heights = c(2, 2, 4))
install.packages("patchwork")
Warning in install.packages :
  package ‘patchwork’ is in use and will not be installed

Argument widths töötab sama moodi.

(p1 | p2 | p3) + plot_layout(widths = c(2, 2, 4))

Eelmine pilt jäi kole sest vastavate laiustega on graafikute andmeid näitavad paneelid. Kuna kahel graafikul on aga legend, siis nende laiust arvesse ei võeta. Küll aga on võimalik argumendiga guides kõikidelt piltidelt legendid kokku koguda.

(p1 | p2 | p3) + plot_layout(widths = c(2, 2, 4), guides = "collect")

Paketis patchwork on veel palju võimalusi ja tasub uurida paketi kodulehte https://github.com/thomasp85/patchwork ja seal viidatud õpetusi.

Ülesanded

  • Proovige tekitada järgnev pilt

(p1 / ( p2 | p3)) + plot_layout(widths = c(2, 2, 4), guides = "collect")

Kodune ülesanne

linnad
library(ggplot2)
library(dplyr)
library(patchwork)


fill_cols <- c(
  "Low"    = "#f4a142",
  "Medium" = "gray90",
  "High"   = "#7b67c8"
)

outline_cols <- c(
  "Low"    = "#e65000",
  "Medium" = "#e65000",
  "High"   = "#e65000"
)


data <- linnad %>% 
  mutate(
    income_class = fct_recode(income_class, "High" = "Very High", "Low" = "Very Low"),
    Poverty_factor = fct_relevel(Poverty_factor, "Low", "Medium", "High"),
    Birth_factor = fct_relevel(Birth_factor, "Low", "Medium", "High") 
  )

p1 <- ggplot(data, aes(x = Birth_factor, y = over65, fill = Birth_factor)) + 
    geom_boxplot(fill = NA, color="gray5") +
    geom_violin(
      aes(color = Birth_factor),
     alpha = 0.4, linewidth = 0,
      draw_quantiles = NULL
    ) +
    scale_fill_manual(values = fill_cols) +
    scale_color_manual(values = outline_cols) +
    geom_hline(yintercept = 12.5, linetype = "dotted") +
    facet_wrap(~ State, ncol = 3) + 
    theme_bw(base_size = 13) +
    theme(
      strip.background = element_rect(fill = "#f2b0c4", color = "black"),
      strip.text = element_text(face = "bold"),
      panel.grid.major.x = element_blank(),
      panel.grid.major.y = element_blank(),
      panel.grid.minor = element_blank(),
      panel.background = element_rect(fill = "white", color = NA),
      legend.position = c(1, -0.1), 
      legend.justification = c(1, 0),
      legend.key = element_rect( color="red"),
    ) 



p2 <- ggplot(linnad, aes(x = deaths, y = births)) +
  geom_point(color = "white", size = 2,) +
  geom_smooth(color = "red", linewidth = 1) +
  theme_void() +
  theme(
    panel.background = element_rect(fill = "black", color = "black"),
    panel.grid.major = element_line(color = "white", linetype = "dashed"),
    panel.grid.minor = element_line(color = "white", linetype = "dashed"),
    axis.text = element_text(color = "black"),
    axis.title = element_text(color = "black"),
    plot.background = element_rect(fill = "white", color = "white"),
    axis.title.y = element_text(angle = 90)
  ) +
    scale_x_continuous(name = "Higher education percentage", breaks = c(0, 0.5, 1, 1.5, 2))+
  labs(x = "deaths", y = "births")


p1 / p2 + plot_layout(heights = c(3, 1))

ggplot2-ga graafikute joonistamise harjutamine

Selle ja eelmise praktikumi põhjal peaks olulisemad oskused ggplot2 kasutamiseks olemas olema. Nüüd proovime neid rakendada, kasutades ka teadmisi teisest loengust, kus sai tutvustatud graafikute valimise põhimõtteid täpsemalt.

Loeme sisse kõigepealt andmestiku, mis kirjeldab siis 2000 inimese kehamassi indekseid ja juhuslikul päeval tehtud sammude arvu. Iga inimese kohta on ka antud sugu, vanus ja vanusegrupp. Loeme andmestiku sisse.

load("bmi.RData", verbose = T)

bmi

Iga ülesande puhul tasub proovida erinevaid variante ja mõelda milline töötab antud olukorras paremini ja miks. Meeldetuletuseks, siin on olulisemad käsud mida vaja võib minna

Ülesanded

  • 1 Milline tehtud sammude jaotus? Millist geomeetrilist esitust võib selle uurimiseks kasutada?

  • 2 Milline on tehtud sammude jaotus sugude kaupa? Vihjed:

    • et joonistada histogrammid üksteise peale tasub panna position = "identity"

    • argument alpha kontrollib värvide läbipaistvust

  • 3 Kumma soo esindajad teevad mediaanis vähem sammusid?

  • 4 Tee läbi see sama võrdlus vanusegruppide kaupa. Kas järeldus on sama?

  • 5 Vaata vanusegruppide arvukust sugude kaupa. Kas jaotus on sarnane või erinev?

  • 6 Kas vanuse ja tehtud sammude vahel on seos? Kas seos tundub lineaarne?

  • 7 Milline on seos kehamassi indeksi ja sammude vahel? Kas seos on lineaarne ja või on tegu millegi keerukamaga?


#1
ggplot(bmi, aes(x = Steps)) +
  geom_histogram()


ggplot(bmi, aes(x = Steps)) +
  geom_histogram(bins = 100)


ggplot(bmi, aes(x = Steps)) +
  geom_density()


ggplot(bmi, aes(x = Steps)) +
  geom_boxplot()


#2
ggplot(bmi, aes(x = Steps, fill=Gender)) +
    geom_histogram(position = "identity", alpha=0.3)


ggplot(bmi, aes(x = Steps, fill=Gender, color=Gender)) +
    geom_histogram(position = "identity", alpha=0.3)



ggplot(bmi, aes(x = Steps, fill=Gender, color=Gender)) +
  geom_density(position = "identity", alpha=0.3)


#3

ggplot(bmi, aes(x = Steps, y=Gender)) +
  geom_boxplot()


#4
ggplot(bmi, aes(x = Steps, y=AgeGroup, fill=Gender)) +
  geom_boxplot()


#5
ggplot(bmi, aes(x = Gender, fill=AgeGroup)) +
  geom_bar()


ggplot(bmi, aes(x = Gender, fill=AgeGroup)) +
  geom_bar(position="dodge")


ggplot(bmi, aes(x = Gender, fill=AgeGroup)) +
  geom_bar(position="fill")


#6
ggplot(bmi, aes(x = Age, y=Steps)) +
  geom_point() +
  geom_smooth()


ggplot(bmi, aes(x = Age, y=Steps)) +
  geom_point() +
  geom_smooth(method = "lm")


#7 
ggplot(bmi, aes(x = BMI, y=Steps)) +
  geom_point() +
  geom_smooth()


ggplot(bmi, aes(y = BMI, x=Steps)) +
  geom_point() +
  geom_smooth(method = "lm")

Kodune ülesanne

Failis ylevaatused.RData on andmestik kõigi Eestis toime pandud sõidukite tehniliste ülevaatuste kohta. Tunnuste kohta lisainfot palju pole, kuid nimed peaks suht selged olema. Andmestik pärineb eesti avaandmete portaalist: https://avaandmed.eesti.ee/datasets/maismaasoidukite-tehnoulevaatused-eestis

Ülesandeks on selle andmestiku põhjal joonistada välja graafik mis toob välja mingi huvitava seose. Andmestik on suur ja graafik ei pea kajastama tervet andmestikku, vaid võib keskenduda mingile andmete alamhulgale.

Sellel graafikul võib olla mitu paneeli, kuid peab olema siiski üks fail, mis välja trükkides mahuks ühele lehele ja oleks loetav. Kuna andmed on keerukad võib pildi salvestada suuremana, kui Rstudio graafiku aknasse mahub (kasutades käsku ggsave ja argumente height ja width), et kõigel vajalikul piisavalt ruumi oleks.

Esitada tuleb graafikut genereeriv kood, põhjendus miks just antud tüüpi graafik(ud) on nende andmete näitamiseks hea ja ka mõne lauseline järeldus, mille te pildilt olete välja lugenud.

Graafik peab vastama järgnevatele tingimustele.


load("ylevaatused.RData", verbose = T)
Loading objects:
  ylevaatused
ylevaatused
names(ylevaatused) # colnames(ylevaatused)
 [1] "TEHNOYLEVAATUSPUNKT" "PUNKTI_KOOD"         "TOOTAJA"             "YV_KUUPAEV"          "YLEVAATUSLIIK"       "YLEVAATUSOTSUS"      "RIKKED"             
 [8] "SOIDUK_ID"           "ESMANE_REG_AASTA"    "MARK"                "MUDEL"               "KATEGOORIA"          "KERETYYP"           
unique(ylevaatused$YLEVAATUSOTSUS)
[1] "KORRAS"              "KORDUVALE"           "VASTAB_NOUETELE"     "SOITMISEKS_KOLBMATU" "KATKESTATUD"         "EI_VASTA_NOUETELE"  
str(ylevaatused)
Classes ‘spec_tbl_df’, ‘tbl_df’, ‘tbl’ and 'data.frame':    720032 obs. of  13 variables:
 $ TEHNOYLEVAATUSPUNKT: chr  "Narva Tehno OÜ (Lääne)" "A-Ülevaatus OÜ (Raua)" "Rehvikeskus OÜ" "PRO Tehno OÜ (Sauga)" ...
 $ PUNKTI_KOOD        : chr  "NH" "DR" "LE" "FK" ...
 $ TOOTAJA            : chr  "440" "631" "0807" "579" ...
 $ YV_KUUPAEV         : chr  "2023-12" "2023-07" "2023-06" "2023-10" ...
 $ YLEVAATUSLIIK      : chr  "KORRALINE" "KORRALINE" "KORRALINE" "KORRALINE" ...
 $ YLEVAATUSOTSUS     : chr  "KORRAS" "KORRAS" "KORRAS" "KORRAS" ...
 $ RIKKED             : chr  NA NA NA NA ...
 $ SOIDUK_ID          : num  1 2 3 4 5 6 7 8 9 10 ...
 $ ESMANE_REG_AASTA   : num  2003 2011 1996 2015 2018 ...
 $ MARK               : chr  "FORD" "PANAV" "HONDA" "KRONE" ...
 $ MUDEL              : chr  "GALAXY" "NS136" "VT 700C" "SDP 27ELB4-CS" ...
 $ KATEGOORIA         : chr  "M1" "O4" "L3e" "O4" ...
 $ KERETYYP           : chr  "MAHTUNIVERSAAL" "KALLUR" "MOOTORRATAS" "MADEL" ...
 - attr(*, "spec")=List of 3
  ..$ cols   :List of 13
  .. ..$ TEHNOYLEVAATUSPUNKT: list()
  .. .. ..- attr(*, "class")= chr [1:2] "collector_character" "collector"
  .. ..$ PUNKTI_KOOD        : list()
  .. .. ..- attr(*, "class")= chr [1:2] "collector_character" "collector"
  .. ..$ TOOTAJA            : list()
  .. .. ..- attr(*, "class")= chr [1:2] "collector_character" "collector"
  .. ..$ YV_KUUPAEV         : list()
  .. .. ..- attr(*, "class")= chr [1:2] "collector_character" "collector"
  .. ..$ YLEVAATUSLIIK      : list()
  .. .. ..- attr(*, "class")= chr [1:2] "collector_character" "collector"
  .. ..$ YLEVAATUSOTSUS     : list()
  .. .. ..- attr(*, "class")= chr [1:2] "collector_character" "collector"
  .. ..$ RIKKED             : list()
  .. .. ..- attr(*, "class")= chr [1:2] "collector_character" "collector"
  .. ..$ SOIDUK_ID          : list()
  .. .. ..- attr(*, "class")= chr [1:2] "collector_double" "collector"
  .. ..$ ESMANE_REG_AASTA   : list()
  .. .. ..- attr(*, "class")= chr [1:2] "collector_double" "collector"
  .. ..$ MARK               : list()
  .. .. ..- attr(*, "class")= chr [1:2] "collector_character" "collector"
  .. ..$ MUDEL              : list()
  .. .. ..- attr(*, "class")= chr [1:2] "collector_character" "collector"
  .. ..$ KATEGOORIA         : list()
  .. .. ..- attr(*, "class")= chr [1:2] "collector_character" "collector"
  .. ..$ KERETYYP           : list()
  .. .. ..- attr(*, "class")= chr [1:2] "collector_character" "collector"
  ..$ default: list()
  .. ..- attr(*, "class")= chr [1:2] "collector_guess" "collector"
  ..$ delim  : chr ","
  ..- attr(*, "class")= chr "col_spec"
 - attr(*, "problems")=<externalptr> 
library(tidyverse)
library(patchwork)
ylev <- ylevaatused %>%
  mutate(
    RIKKED = ifelse(is.na(RIKKED), "", RIKKED),
    VIGADE_ARV = ifelse(RIKKED == "", 0, str_count(RIKKED, ";") + 1),
  ) %>%
  filter(str_starts(KATEGOORIA, "M") & !is.na(KATEGOORIA)) %>%
 mutate(KERETYYP_GRUPP = case_when(
    KERETYYP %in% c("MAHTUNIVERSAAL", "UNIVERSAAL", "LUUKPÄRA", "SEDAAN",
                    "KUPEE", "LIMUSIIN", "KOMBI") ~ "Sõiduauto",

    KERETYYP %in% c("LAHTINE", "PIKAP", 
                    "SIHTOTSTARBELINE", "ERIOTSTARBELINE SÕIDUK") ~ "Kaubik / tööauto",

    KERETYYP %in% c("MITMEOTSTARBELINE SÕIDUK") ~ "Mitmeotstarbeline",

    KERETYYP %in% c("BUSS", "LIIGENDBUSS", "KORRUSBUSS", "TROLL") ~ "Buss",

    KERETYYP %in% c("KIIRABI", "MATUSEAUTO", "ELAMU") ~ "Erisõiduk",

    TRUE ~ NA
  ))
  #sample_n(20000)

ylev
#unique(ylev$YLEVAATUSOTSUS)

unique(ylev$KERETYYP)
 [1] "MAHTUNIVERSAAL"           "UNIVERSAAL"               "LAHTINE"                  "LUUKPÄRA"                 "SEDAAN"                  
 [6] "ELAMU"                    "MITMEOTSTARBELINE SÕIDUK" "BUSS"                     "SIHTOTSTARBELINE"         "KUPEE"                   
[11] "LIIGENDBUSS"              "KIIRABI"                  "PIKAP"                    "ERIOTSTARBELINE SÕIDUK"   "LIMUSIIN"                
[16] "MATUSEAUTO"               NA                         "KORRUSBUSS"               "KOMBI"                    "TROLL"                   
# Vanus vs mitte_positiivne ülevaatusotsus (M1 ja m1g kategooria (sõiduuatod ja bussid))

library(scales)
palett = hue_pal()(8)

kategooria_värvid = c(
  "M1"     = palett[2],
  "M1G"    = palett[4],
  "M2"     = palett[6],
  "M3"     = palett[8]
)


m1_m1g <- ylev %>%
  filter(!is.na(ESMANE_REG_AASTA), !is.na(YLEVAATUSOTSUS)) %>%
  filter(YLEVAATUSOTSUS %in% c("EI_VASTA_NOUETELE", "SOITMISEKS_KOLBMATU")) %>%
  filter(KATEGOORIA %in% c("M1", "M1G")) %>%
  ggplot(aes(x = ESMANE_REG_AASTA, color = KATEGOORIA, fill = KATEGOORIA)) +
  geom_density(alpha = 0.2) +
  labs(
    title = "Sõiduautod",
    x = "Esmane registreerimse aasta",
    y = "Tihedus",
    fill = "Kategooria",
    color = "Kategooria"
  ) +
  theme_minimal(base_size = 12) +
  theme(plot.title = element_text(face = "plain", size = 12)) +
  scale_color_manual(values = kategooria_värvid) +
  scale_fill_manual(values = kategooria_värvid) 

m2_m3 <- ylev %>%
  filter(!is.na(ESMANE_REG_AASTA), !is.na(YLEVAATUSOTSUS)) %>%
  filter(YLEVAATUSOTSUS %in% c("EI_VASTA_NOUETELE", "SOITMISEKS_KOLBMATU")) %>%
  filter(KATEGOORIA %in% c("M2", "M3")) %>%
  ggplot(aes(x = ESMANE_REG_AASTA, color = KATEGOORIA, fill = KATEGOORIA)) +
  geom_density(alpha = 0.2) +
  labs(
    title = "Bussid",
    x = "Esmane registreerimse aasta",
    y = "Tihedus",
    fill = "Kategooria",
    color = "Kategooria"
  ) +
  theme_minimal(base_size = 12) +
  theme(plot.title = element_text(face = "plain", size = 12)) +
  scale_color_manual(values = kategooria_värvid) +
  scale_fill_manual(values = kategooria_värvid) 


graafik1 <- m1_m1g / m2_m3 +
   plot_layout(guides = "collect") +
   plot_annotation(
    title = "Negatiivne ülevaatusotsus",
    subtitle = "M-kategooria sõidukid",
    #caption = "Allikas: ?? trust me bro",
    theme = theme(
      plot.title = element_text(face = "bold", size = 16),
      plot.subtitle = element_text(size = 12)
    )
  ) 

#graafik1


# Auto kategooria ja vigade arv
graafik2 <- ylev %>%
  filter(!is.na(KATEGOORIA), !is.na(KERETYYP_GRUPP)) %>%
  group_by(KATEGOORIA) %>%
  ggplot(aes(y = KATEGOORIA, x = VIGADE_ARV, color=KERETYYP_GRUPP)) +
  geom_point(position = "jitter") +
  labs(
    title = "Vigade arv keretüübi kohta",
    subtitle = "M-kategooria sõidukid",
    y = "Keretüüp",
    x = "Vigade Arv",
    color = "Keretüüp"
  ) +
  theme_minimal(base_size = 12) + 
   theme(
      plot.title = element_text(face = "bold", size = 16),
      plot.subtitle = element_text(size = 12)
    )

#graafik2

graafik1 / graafik2 +
   plot_layout(guides = "keep")

Ma tahtsin uurida järgnevat:

  1. Mida vanem auto seda suurema tõenäosusega kukub ülevaatusel auto läbi.

  2. Sõiduautodel on tavaliselt rohkem vigu kui bussidel, kuna autosid on rohkem teedel kui busse.

Järeldused:

  1. sõiduautod: Mida vanem auto, seda suurem on tõenäosus ülevaatusel läbi kukkuda.
    Bussid: Vanus ei selgita otseslet läbikukkumist. Busside puhul mõjutab tulemust pigem asutusintensiivsus (suurem aastane läbisõit), mistõttu võivad ka uuemad bussid sagedamini läbi kukkuda.

  2. Sõiduautodel on rohkem äärmuslikke vigade väärtusi, kuna sõiduautosid on valimis tunduvalt rohkem kui busse. Valimi suurus tekitab loomulikult suurema hajuvuse.

LS0tDQp0aXRsZTogIlByYWt0aWt1bSA4IC0gZ2dwbG90MiBqw6R0ayINCm91dHB1dDogaHRtbF9ub3RlYm9vaw0KLS0tDQoNCiMjIFNpc3NlanVoYXR1cw0KDQpTaWluIHByYWt0aWt1bWlzIGrDpHRrYW1lIGdncGxvdDIgdsO1aW1hbHVzdGUgw7VwcGltaXNlZ2EuIFNlbGxla3MsIGV0IHTDtsO2Z2EgcGlodGEgc2Fha3MgaGFrYXRhLCBsb2VtZSBzaXNzZSB2YWphbGlrdWQgcGFrZXRpZCBqYSBhbmRtZXN0aWt1Lg0KDQpgYGB7cn0NCmxpYnJhcnkoZ2dwbG90MikNCmxpYnJhcnkodGlkeXZlcnNlKQ0KDQpsb2FkKCJsaW5uYWQuUkRhdGEiLCB2ZXJib3NlID0gVCkNCmBgYA0KDQojIyBGYWt0b3JpdGVnYSB0w7bDtnRhbWluZQ0KDQpQYWtldHQgZ2dwbG90MiDDvHJpdGFiIHbDtWltYWxpa3VsdCBwYWxqdSBrYXN1dGFkYSBqb29uaXN0YW1pc2VsIGluZm9ybWF0c2lvb25pIG1pcyBvbiBrb2RlZXJpdHVkIGZha3RvcmkgdGFzZW1ldGVzc2UuwqBGYWt0b3Igb24gYW5kbWV0w7zDvHAgZGlza3JlZXRzZXRlbGUgbXV1dHVqYXRlbGUsIG1pcyBzw6RpbGl0YWIgbGlzYWtzIHbDpMOkcnR1c3RlbGUga2EgaW5mbyBrw7xpZ2kgdsO1aW1hbGlrZSB2w6TDpHJ0dXN0ZSBuaW5nIG5lbmRlIGrDpHJqZXN0dXN0ZSBrb2h0YS4gRmFrdG9yaSB0YXNlbWUgbmltZWRlIHDDtWhqYWwgam9vbmlzdGF0YWtzZSBuw6RpdGVrcyBsZWdlbmQgamEgdGFzZW1lIGrDpHJqZXN0dXN0IGthc3V0YXRha3NlIHRlbGdlZGVsIGVsZW1lbnRpZGUgasOkcmplc3RhbWlzZWtzLiBTZWV0w7V0dHUgb24gb2x1bGluZSB0dW5kYSBwYWFyaSBuaXBwaSBrdWlkYXMgZmFrdG9yaXRlIHRhc2VtZXRlZ2EgdMO2w7Z0YWRhLsKgDQoNCkVzaXRla3Mgb24ga2FzdWxpayBwYW5uYSBmYWt0b3JpIHRhc2VtZXRlbGUgc2lzdWthZCBuaW1lZC4gU2VkYSBzYWFiIHRlaGEgYW5kZXMga8Okc3VsZSBgZmFjdG9yYCBldHRlIGp1YmEgc2lzdWthdGUgbmltZWRlZ2Egc8O1bmV2ZWt0b3JpLCBrYXN1dGFkZXMgYXJndW1lbnRpIGBsYWJlbHNgLg0KDQpgYGB7cn0NCmEgPSBmYWN0b3IoYygxLCAxLCAxLCAyLCAyLCAzKSwgbGFiZWxzID0gYygiQSIsICJCIiwgIkMiKSkNCmENCmBgYA0KDQpGYWt0b3JpIHRhc2VtZXRlIG5pbWVzaWQgc2FhYiBtdXV0YSBrYXN1dGFkZXMga8Okc2t1IGBmY3RfcmVjb2RlYCAodHVsZWIga2Fhc2EgYHRpZHl2ZXJzZWAgcGFrZXRpZ2EpLiBTZWxsZWdhIHNhYWIga2EgZmFrdG9yaSB0YXNlbWVpZCBrb2trdSB2w7V0dGEuDQoNCmBgYHtyfQ0KZmN0X3JlY29kZShhLCAiSSIgPSAiQSIsICJJSSIgPSAiQiIsICJJSUkiID0gIkMiKQ0KDQpmY3RfcmVjb2RlKGEsICJJIiA9ICJBIiwgIklJIiA9ICJCIikNCg0KZmN0X3JlY29kZShhLCAiSSIgPSAiQSIsICJJSSIgPSAiQiIsICJJIiA9ICJDIikNCmBgYA0KDQpGYWt0b3JpIHRhc2VtZXRlIGrDpHJqZXN0dXN0IHNhYWIgbXV1dGEga2Ega8Okc3VnYSBgZmN0X3JlbGV2ZWxgLCBrdXMgZXR0ZWFudHVkIHRhc2VtZWQgdMO1c3RldGFrc2UgasOkamVrb3JyYXMgZXR0ZSBwb29sZQ0KDQpgYGB7cn0NCmEgPSBmYWN0b3IoYygxLCAxLCAxLCAyLCAyLCAzKSwgbGFiZWxzID0gYygiQSIsICJCIiwgIkMiKSkNCmENCg0KZmN0X3JlbGV2ZWwoYSwgIkMiKQ0KZmN0X3JlbGV2ZWwoYSwgIkMiLCAiQiIsICJBIikNCmBgYA0KDQpLdWkgbWUgdGFoYW1lIG11dXRhIGZha3Rvcml0ZSBqw6RyamVrb3JkYSBtaW5naSB0ZWlzZSB2ZWt0b3JpIGrDpHJnaSwgc2lpcyBzYWFiIGthc3V0YWRhIGvDpHNrdSBgZmN0X3Jlb3JkZXJgLg0KDQpgYGB7cn0NCmEgPSBmYWN0b3IoYygxLCAxLCAxLCAyLCAyLCAzKSwgbGFiZWxzID0gYygiQSIsICJCIiwgIkMiKSkNCmIgPSBjKDEsIDUsIDYsIDIsIC00LCAxMCkNCmENCmINCg0KZmN0X3Jlb3JkZXIoYSwgYikNCmZjdF9yZW9yZGVyKGEsIGIsIC5kZXNjID0gVCkNCmZjdF9yZW9yZGVyKGEsIGIsIC5mdW4gPSBtYXgpDQoNCmBgYA0KDQpTZWVnYSBrdWkgbWUgdGFoYW1lIG11Z2FuZGFkYSBwaWx0aSBvbiB0aWh0aXBlYWxlIGthc3VsaWt1bSBlbm5lIG11Z2FuZGFkYSBhbmRtZWlkIGphIHNpaXMgbmVuZGVnYSBwaWx0IGpvb25pc3RhZGEuDQoNCmBgYHtyfQ0KZ2dwbG90KGxpbm5hZCwgYWVzKHggPSBwZXJfY2FwaXRhX2luYywgeSA9IHVuZW1wbG95bWVudF9yYXRlLCBjb2xvdXIgPSBpbmNvbWVfY2xhc3MpKSArDQogIGdlb21fcG9pbnQoKSANCg0KbGlubmFkICU+JSANCiAgbXV0YXRlKGluY29tZV9jbGFzcyA9IGZjdF9yZWNvZGUoaW5jb21lX2NsYXNzLCAiSGlnaCIgPSAiVmVyeSBIaWdoIiwgIkxvdyIgPSAiVmVyeSBMb3ciLCAiTG93IiA9ICJNZWRpdW0iKSkgJT4lIA0KICBnZ3Bsb3QoYWVzKHggPSBwZXJfY2FwaXRhX2luYywgeSA9IHVuZW1wbG95bWVudF9yYXRlLCBjb2xvdXIgPSBpbmNvbWVfY2xhc3MpKSArDQogICAgZ2VvbV9wb2ludCgpIA0KYGBgDQoNCmBgYHtyfQ0KZ2dwbG90KGxpbm5hZCwgYWVzKHggPSBwZXJfY2FwaXRhX2luYywgeSA9IHVuZW1wbG95bWVudF9yYXRlLCBjb2xvdXIgPSBQb3ZlcnR5X2ZhY3RvcikpICsNCiAgZ2VvbV9wb2ludCgpIA0KDQpsaW5uYWQgJT4lIA0KICBtdXRhdGUoUG92ZXJ0eV9mYWN0b3IgPSBmY3RfcmVsZXZlbChQb3ZlcnR5X2ZhY3RvciwgIkxvdyIsICJNZWRpdW0iLCAiSGlnaCIpKSAlPiUgDQogIGdncGxvdChhZXMoeCA9IHBlcl9jYXBpdGFfaW5jLCB5ID0gdW5lbXBsb3ltZW50X3JhdGUsIGNvbG91ciA9IFBvdmVydHlfZmFjdG9yKSkgKw0KICBnZW9tX3BvaW50KCkgDQpgYGANCg0KYGBge3J9DQpnZ3Bsb3QobGlubmFkLCBhZXMoeCA9IENvdW50eSwgeSA9IHBvcF9lc3RpbWF0ZSkpICsNCiAgZ2VvbV9iYXIoc3RhdCA9ICJpZGVudGl0eSIpIA0KDQpsaW5uYWQgJT4lIA0KICBtdXRhdGUoQ291bnR5ID0gZmN0X3Jlb3JkZXIoQ291bnR5LCBwb3BfZXN0aW1hdGUpKSAlPiUgDQogIGdncGxvdChhZXMoeCA9IENvdW50eSwgeSA9IHBvcF9lc3RpbWF0ZSkpICsNCiAgICBnZW9tX2JhcihzdGF0ID0gImlkZW50aXR5IikgDQpgYGANCg0KIyMjIyDDnGxlc2FuZGVkDQoNCi0gICBKb29uaXN0YWdlIHNlb3MgKmJhY2hlbG9yKiBqYSAqaGlnaF9zY2wqIHZhaGVsIG5pbmcgbsOkaWRha2UgdsOkcnZpZ2EgdHVubnVzdCAqaW5jb21lX2NsYXNzKiAuIFbDtXRhIGtva3Uga2xhc3NpZCAiVmVyeSBMb3ciIGphICJMb3ciIG5pbmcgdXVkYSB2w6RydmlkZSBqw6RyamVrb3JkIG5paSwgZXQgc2VlIGFsZ2FrcyB2w6RnYSBrw7VyZ2VzdCBqYSBsw7VwcGVrcyBtYWRhbGFnYS4NCg0KYGBge3J9DQoNCmxpbm5hZCAlPiUgDQogIG11dGF0ZShpbmNvbWVfY2xhc3MgPSBmY3RfcmVjb2RlKGluY29tZV9jbGFzcywgIkxvdyIgPSAiVmVyeSBMb3ciKSkgJT4lDQogIG11dGF0ZShpbmNvbWVfY2xhc3MgPSBmY3RfcmVsZXZlbChpbmNvbWVfY2xhc3MsICJMb3ciLCAiTWVkaXVtIiwgIkhpZ2giLCAiVmVyeSBIaWdoIiApKSAlPiUgDQogIGdncGxvdChhZXMoeCA9IGJhY2hlbG9yICwgeSA9IGhpZ2hfc2NsICwgY29sb3VyID0gaW5jb21lX2NsYXNzICkpICsNCiAgZ2VvbV9wb2ludCgpIA0KYGBgDQoNCiMjIEdyYWFmaWt1dGUgYW5ub3RlZXJpbWluZSBqYSBtdWdhbmRhbWluZQ0KDQojIyMgR3JhYWZpa3V0ZSBhbm5vdGVlcmltaW5lDQoNClRlbGdlZGUgamEgZ3JhYWZpa3UgYW5ub3RlZXJpbWlzZSB2aWlzZSBtZSBvbGVtZSBqdWJhIHTDtsO2IGvDpGlndXMgbsOkaW51ZC4gUGFsanVkIGFzamFkIHNhYWIgw6RyYSBsYWhlbmRhZGEgZXJpbmV2YXRlIHNrYWxlZXJpbWlzZnVua3RzaW9vbmlkZSBwYXJhbWVldHJpdGVnYS4gU2lpc2tpIG9uIHBhbGp1ZGVsZSBuZWlzIG9sZW1hcyBrYSBtdWdhdmFtYWQgdmFzdGVkIGVyYWxkaSBmdW5rdHNpb29uaWRlZ2EgbWlzIGhvaWF2YWQgdHLDvGtraW1pc3Qga29ra3UuIE5laXN0IG9sdWxpc2VtYWQgb27CoA0KDQotICAgYGdndGl0bGUoKWAgLSBtw6TDpHJhbWUgZ3JhYWZpa3UgcGVhbGtpcmphDQoNCi0gICBgeGxhYigpYCwgYHlsYWIoKWAgLSB0ZWxnZWRlIHBlYWxraXJqYWQNCg0KLSAgIGB4bGltKClgLCBgeWxpbSgpYCAtIHRlbGdlZGUgdsOkw6RydHVzdmFoZW1pa3UgbcOkw6RyYW1pbmUNCg0KIyMjIEdyYWFmaWt1dGUgc3RpaWwNCg0KVmFoZXN0IG9uIHZhamEgbXV1dGEgYGdncGxvdDJgIGdyYWFmaWt1dGUgw7xsZcO8bGRpc3Qgc3RpaWxpIHbDtWkgbcO1bmUgZWxlbWVuZGkgdsOkbGphbsOkZ2VtaXN0LiBOw6RpdGVrcyBvbiBzdGFuZGFyZG5lIGBnZ3Bsb3QyYCBncmFhZmlrdXRlIHRhdXN0IGhhbGwsIG1pcyBlaSBvbGUgYWxhdGkgcGFyaW0gbGFoZW5kdXMuIFNlZGEgb24gbGlodG5lIG11dXRhIGvDpHN1Z2EgYHRoZW1lX2J3YCBtaXMgdGVlYiB0YXVzdGEgdmFsZ2VrcyBqYSBtdXVkYWIga2EgcG9ydHN1IG11dWRlIGdyYWFmaWt1IGVsZW1lbnRpZGUgdsOkcnZlIGphIGt1anUuDQoNCmBgYHtyfQ0KZ2dwbG90KGxpbm5hZCwgYWVzKHggPSBwZXJfY2FwaXRhX2luYywgeSA9IHVuZW1wbG95bWVudF9yYXRlLCBjb2xvdXIgPSBiaXJ0aF9jbGFzcykpICsNCiAgZ2VvbV9wb2ludCgpICsNCiAgdGhlbWVfYncoKSANCmBgYA0KDQpOZWlkIGZ1bmt0c2lvb25lIG9uIHZlZWwsIHRhc3ViIHZhYWRhdGEgbWlkYSBSU3R1ZGlvIHBha3ViLCBrdWkga2lyanV0YWRhIGFsZ3VzIGB0aGVtZV9gIC4gVmVlbCByb2hrZW0gZXJpbmV2YWlkIHRlZW1hc2lkIG9uIG9sZW1hcyBwYWtldGlzIGBnZ3RoZW1lc2AgKDxodHRwczovL3l1dGFubmloaWxhdGlvbi5naXRodWIuaW8vYWxsWW91ckZpZ3VyZUFyZUJlbG9uZ1RvVXMvZ2d0aGVtZXMvPikuDQoNCmBgYHtyfQ0KbGlicmFyeShnZ3RoZW1lcykNCmdncGxvdChsaW5uYWQsIGFlcyh4ID0gcGVyX2NhcGl0YV9pbmMsIHkgPSB1bmVtcGxveW1lbnRfcmF0ZSwgY29sb3VyID0gYmlydGhfY2xhc3MpKSArDQogIGdlb21fcG9pbnQoKSArDQogIHRoZW1lX3dzaigpIA0KYGBgDQoNClTDpHBzZW1hbHQgc2FhYiBtdXV0YSBrb25rcmVldHNlaWQgZWxlbWVudGUga8Okc3VnYSBgdGhlbWVgLiBTaWluIG9uIHRlcnZlIHBvcnRzIHBhcmFtZWV0cmVpZCBtaXMgdMO2w7Z0YXZhZCBoaWVyYXJoaWxpc2VsdC4gT2x1bGlzZW1hZCBvbiB0b29kdWQgasOkcmdtaXNlbCBqb29uaXNlbC4NCg0KIVshW10oaW1hZ2VzL2NsaXBib2FyZC05NzkzMzc1MDMucG5nKV0oaW1hZ2VzL1NjcmVlbnNob3QlMjAyMDIxLTAyLTIyJTIwYXQlMjAxMC41NC4xOC5wbmcpDQoNCk5lbmRlbGUgc2FhYnbDpMOkcnR1c2VrcyBhbmRhIGvDpHNrZSBgZWxlbWVudF90ZXh0YCwgYGVsZW1lbnRfbGluZWAgamEgYGVsZW1lbnRfcmVjdGAgdmFzdGF2YWx0IHBhcmFtZWV0cmkgdMO8w7xiaWxlLiBLw6Rza3VkZSBgZWxlbWVudF8qYCBwYXJhbWVldHJpZCB2YXN0YXZhZCBzdWh0ZWxpc2VsdCB0w6Rwc2VsdCBzYXJuYXN0ZSBlbGVtZW50aWRlIGdyaWQgcGFrZXRpcyBrYXN1dGF0YXZhdGVsZSBwYXJhbWVldHJpdGVsZS4gT2x1bGluZSBmdW5rdHNpb29uIG9uIGthIGVsZW1lbnRfYmxhbmsgbWlzIHZhc3RhdmEgZWxlbWVuZGkgbGlodHNhbHQgw6RyYSBrdXN0dXRhYi4NCg0KYGBge3J9DQpnZ3Bsb3QobGlubmFkLCBhZXMoeCA9IHBlcl9jYXBpdGFfaW5jLCB5ID0gdW5lbXBsb3ltZW50X3JhdGUsIGNvbG91ciA9IGJpcnRoX2NsYXNzKSkgKw0KICBnZW9tX3BvaW50KCkgKw0KICB0aGVtZShwYW5lbC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGZpbGwgPSAicGluayIpLCBwYW5lbC5ncmlkLm1pbm9yID0gZWxlbWVudF9ibGFuaygpKQ0KYGBgDQoNClbDpGdhIG9sdWxpbmUgcGFyYW1lZXRlciBrw6RzdXMgdGhlbWUgb24ga2EgYGxlZ2VuZC5wb3NpdGlvbmAuIEt1aSBzZWxsZSB2w6TDpHJ0dXNla3Mgb24gYCJub25lImAga3VzdHV0YXRha3NlIGxlZ2VuZCDDpHJhLiBWw6TDpHJ0dXNlZCBgImxlZnQiYCwgYCJyaWdodCJgLCBgInRvcCJgIGphIGAiYm90dG9tImAga8OkaXR1dmFkIG5hZ3UgdsO1aWtzIG9vZGF0YSAuIEFuZGVzIGV0dGUga2FoZSBlbGVtZW5kaWxpc2UgdmVrdG9yaSBwYWlndXRhYiB0YSBsZWdlbmRpIGdyYWFmaWt1IGFsYSBzZWVzIHZhc3RhdmFsdCBhbnR1ZCBrb29yZGluYWF0aWRlbGUsIHBhcmFsbGVlbHNlbHQgb24gaGVhIGthc3V0YWRhIGthIGBsZWdlbmQuanVzdGlmaWNhdGlvbmAgYXJndW1lbnRpLCBtaXMgdsO1aW1hbGRhYiBsZWdlbmRpIHBhaWd1dHVzdCB0w6Rwc2VtYWx0IGtvbnRvbGxpZGEuDQoNCmBgYHtyfQ0KZ2dwbG90KGxpbm5hZCwgYWVzKHggPSBwZXJfY2FwaXRhX2luYywgeSA9IHVuZW1wbG95bWVudF9yYXRlLCBjb2xvdXIgPSBiaXJ0aF9jbGFzcykpICsNCiAgZ2VvbV9wb2ludCgpICsNCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKQ0KYGBgDQoNCmBgYHtyfQ0KZ2dwbG90KGxpbm5hZCwgYWVzKHggPSBwZXJfY2FwaXRhX2luYywgeSA9IHVuZW1wbG95bWVudF9yYXRlLCBjb2xvdXIgPSBiaXJ0aF9jbGFzcykpICsNCiAgZ2VvbV9wb2ludCgpICsNCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gImJvdHRvbSIpDQpgYGANCg0KYGBge3J9DQpnZ3Bsb3QobGlubmFkLCBhZXMoeCA9IHBlcl9jYXBpdGFfaW5jLCB5ID0gdW5lbXBsb3ltZW50X3JhdGUsIGNvbG91ciA9IGJpcnRoX2NsYXNzKSkgKw0KICBnZW9tX3BvaW50KCkgKw0KICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSBjKDEsMSksIGxlZ2VuZC5qdXN0aWZpY2F0aW9uID0gYygxLCAxKSkNCmBgYA0KDQojIyMjIMOcbGVzYW5kZWQNCg0KLSAgIFByb292aSBzYWF2dXRhZGEgdW1iZXMgasOkcmdtaW5lIHBpbHQuDQoNCiFbXShpbWFnZXMvU2NyZWVuc2hvdCUyMDIwMjEtMDItMjglMjBhdCUyMDE2LjMxLjU0LnBuZykNCg0KYGBge3J9DQpnZ3Bsb3QobGlubmFkLCBhZXMoeCA9IGJhY2hlbG9yLCB5ID0gaGlnaF9zY2wsIGNvbG91ciA9IGluY29tZV9jbGFzcykpICsNCiAgZ2VvbV9wb2ludCgpICsNCiAgc2NhbGVfY29sb3JfYnJld2VyKHR5cGU9ImRpdiIsIHBhbGV0dGU9MikgKw0KICBnZ3RpdGxlKCJIaWdoIFNjaG9vbCBhbmQgSGlnaGVyIEVkdWNhdGlvbiIpICsNCiAgdGhlbWUoDQogICAgcGFuZWwuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChmaWxsID0gImdvbGQiKSwNCiAgICBheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZT00NSksDQogICAgbGVnZW5kLnBvc2l0aW9uID0gYygxLDApLCANCiAgICBsZWdlbmQuanVzdGlmaWNhdGlvbiA9IGMoMSwgMCksDQogICAgbGVnZW5kLmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoY29sb3IgPSAiYmxhY2siKSwNCiAgICBsZWdlbmQua2V5ID0gZWxlbWVudF9yZWN0KGZpbGwgPSAiZ3JleTk1IikNCiAgKQ0KYGBgDQoNCiMjIEdyYWFmaWt1dGUgc2FsdmVzdGFtaW5lDQoNCkdyYWZpa3VpZCBzYWFiIHNhbHZlc3RhZGEga8Okc3VnYSBgZ2dzYXZlKClgLCBLdWkgZXR0ZSBhbmRhIHZhaWQgZmFpbGkgbmltaSwgc2lpcyBzYWx2ZXN0YWIgc2VlIGvDpHNrIHZpaW1hc2UgZ3JhYWZpa3UsIG1pcyBzYWkgam9vbmlzdGF0dWQsIGt1c2p1dXJlcyBzdXVydXNlIHbDtXRhYiB0YSBha25hIGrDpHJnaSBuaW5nIGZhaWxpdMO8w7xiaSBtw6TDpHJhYiBmYWlsaSBuaW1lIGxhaWVuZGkgasOkcmdpLg0KDQpQYXJhbWVldHJlaWQgYHdpZHRoYCBqYSBgaGVpZ2h0YCBrYXN1dGFkZXMgb24gdsO1aW1hbGlrIMOkcmEgbcOkw6RyYXRhIGthIHTDpHBzZWx0IGpvb25pc2UgbcO1w7VkdWQgKHRvbGxpZGVzKS4NCg0KYGBge3J9DQpnZ3Bsb3QobGlubmFkLCBhZXMoeCA9IHBlcl9jYXBpdGFfaW5jLCB5ID0gdW5lbXBsb3ltZW50X3JhdGUsIGNvbG91ciA9IFBvdmVydHlfZmFjdG9yKSkgKw0KICBnZW9tX3BvaW50KCkgKw0KICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSBjKDEsMSksIGxlZ2VuZC5qdXN0aWZpY2F0aW9uID0gYygxLCAxKSkNCg0KZ2dzYXZlKCJwbG90MS5wbmciKQ0KZ2dzYXZlKCJwbG90MS5wZGYiKQ0KZ2dzYXZlKCJwbG90MV93aWRlLnBuZyIsIHdpZHRoID0gMTAsIGhlaWdodCA9IDUpDQpgYGANCg0KU29vdml0YXYgb24gc2FsdmVzdGFkYSBqb29uaXNlaWQgLnBkZiBmb3JtYWFkaXMuIE5paSB0ZWhha3NlIHZla3RvcmdyYWFmaWthIGphIHBpbHQgb24gYWxhdGkgaGVhIGt2YWxpdGVlZGlnYS4gS3VpIHNvb3ZpZGEgKFdpbmRvd3NpbCksIGV0IGthcyByYXN0ZXIga3VqdWwgc2FsdmVzdGF0dWQgcGlsZGlkIG7DpGl0ZWtzIC5wbmcgZmFpbGlkIGhlYWQgdsOkbGphIG7DpGVrc2lkIHRhc3ViIG11dXRhIHZhaWtpbWlzaSBncmFhZmlrYSBtb290b3JpdCBSU3R1ZGlvcyBqw6RyZ25ldmFsdC4NCg0KIVtdKGltYWdlcy9pbWFnZS5wbmcpDQoNCiMjIEVyaW5ldmF0ZSBncmFhZmlrdXRlIGtva2t1IHBhbmVtaW5lDQoNCkdyYWFmaWt1dGUgdGFoa3VkZWtzIGphZ2FtaW5lIHRvaW1pYiB2w6RnYSBow6RzdGksIGt1aSBtZSB0YWhhbWUgw7xodGUgdMO8w7xwaSBncmFhZmlrdXQgamFnYWRhIG1pdG1la3MuIEt1aWQga3VpIG1lIHRhaGFtZSBlcmluZXZhdCB0w7zDvHBpIGdyYWFmaWt1aWQgZXJpbmV2YXRlbCBtdXV0dWphdGVsIHNhbWFsIHBpbGRpbCBrw7VydnV0aSBuw6RpZGF0YSwgc2lpcyBzYW1hIGzDpGhlbmVtaW5lIGVpIHTDtsO2dGEuIFNpaW4gdHVsZXZhZCBhcHBpIGxpc2FwYWtldGlkLiBOw6RpdGVrcyBgcGF0Y2h3b3JrYCBvbiDDvGtzIG1pcyB2w7VpbWFsZGFiIGBnZ3Bsb3QyYCBncmFhZmlrdWlkIGtva2t1IHBhbm5hLg0KDQpFbm5lLCBrdWkgbMOkaGVtZSBgcGF0Y2h3b3JrYC1pIGVuZGEganV1cmRlIHZhYXRhbWUgw7xodGUga2FzdWxpa2t1IG5pcHBpLiBOaW1lbHQgb24gdsO1aW1hbGlrIGdncGxvdCBncmFhZmlrIG11dXR1amFuYSBzYWx2ZXRhZGEuIEpvb25pc3RhdGFrc2Ugc2VlIGFsbGVzIHNpaXMga3VpIG11dXR1amEgdsOkw6RydHVzIG9uIHZhamEgdsOkbGphIHRyw7xra2lkYS4NCg0KYGBge3J9DQpwID0gZ2dwbG90KGxpbm5hZCwgYWVzKHggPSBwZXJfY2FwaXRhX2luYywgeSA9IHVuZW1wbG95bWVudF9yYXRlLCBjb2xvdXIgPSBQb3ZlcnR5X2ZhY3RvcikpICsNCiAgZ2VvbV9wb2ludCgpDQoNCnANCnAgKyB0aGVtZV9idygpDQpgYGANCg0KTG9lbWUgc2lzc2UgcGFrZXRpIHBhdGNod29yayBqYSBkZWZpbmVlcmltZSBrb2xtIGdyYWFmaWt1dCBtaWRhIGtvbWJpbmVlcmltYSBoYWthdGEuDQoNCmBgYHtyfQ0KaW5zdGFsbC5wYWNrYWdlcygicGF0Y2h3b3JrIikNCmBgYA0KDQpgYGB7cn0NCmxpYnJhcnkocGF0Y2h3b3JrKQ0KDQpwMSA9IGdncGxvdChsaW5uYWQsIGFlcyh4ID0gcGVyX2NhcGl0YV9pbmMpKSArDQogIGdlb21faGlzdG9ncmFtKCkgKw0KICBnZ3RpdGxlKCJQbG90IDEiKQ0KcDIgPSBnZ3Bsb3QobGlubmFkLCBhZXMoeCA9IHBlcl9jYXBpdGFfaW5jLCB5ID0gdW5lbXBsb3ltZW50X3JhdGUsIGNvbG91ciA9IFBvdmVydHlfZmFjdG9yKSkgKw0KICBnZW9tX3BvaW50KCkgKw0KICBnZ3RpdGxlKCJQbG90IDIiKQ0KcDMgPSBnZ3Bsb3QobGlubmFkLCBhZXMoeCA9IFN0YXRlLCB5ID0gdW5lbXBsb3ltZW50X3JhdGUsIGZpbGwgPSBTdGF0ZSkpICsNCiAgZ2VvbV9ib3hwbG90KCkgKw0KICBnZ3RpdGxlKCJQbG90IDMiKQ0KDQoNCnAxDQpwMg0KcDMNCmBgYA0KDQpQYXRjaHdvcmtpcyB0ZWhha3NlIGthIGdyYWFmaWt1dGVnYSAidGVodGVpZCIuIFNlbGxla3MsIGV0IGdyYWFmaWt1aWQga8O1cnZ1dGkgcGFubmEgb24gdGVoZSBgfGAuDQoNCmBgYHtyfQ0KcDEgfCBwMiAgDQpgYGANCg0Kw5xrc3RlaXNlIGFsbGEgc2FhYiBwYW5uYSBncmFhZmlrdWlkIHRlaHRlZ2EgYC9gIC4NCg0KYGBge3J9DQpwMS9wMg0KYGBgDQoNClRlaHRlaWQgc2FhYiBrYSBrb21iaW5lZXJpZGEsIHNpaXMgdHVsZWIgdMOkaGVsZXBhbnUganVodGlkYSB0ZWhldGUgasOkcmpla29ycmFsZQ0KDQpgYGB7cn0NCnAxIHwgcDIgLyBwMw0KYGBgDQoNCmBgYHtyfQ0KKHAxIHwgcDIpIC8gcDMNCmBgYA0KDQpTZWxsZWtzLCBldCBwaWx0aWRlIHBhaWd1dHVzdCBwYXJlbWluaSBrb250cm9sbGlkYSBvbiBmdW5rdHNpb29uIGBwbG90X2xheW91dGAsIG1pbGxlZ2Egc2FhYiBqb29uaXNlIGVyaW5ldmFpZCBhc3Bla3RlIG11dXRhLiBOw6RpdGVrcyBgaGVpZ2h0c2AgcGFyYW1lZXRlciB2w7VpbWFsZGFiIG11dXRhIHBpbHRpZGUgc3VodGVsaXNpIGvDtXJndXNlaWQuDQoNCmBgYHtyfQ0KcDEgLyBwMiAvIHAzICsgcGxvdF9sYXlvdXQoaGVpZ2h0cyA9IGMoMiwgMiwgNCkpDQpgYGANCg0KQXJndW1lbnQgd2lkdGhzIHTDtsO2dGFiIHNhbWEgbW9vZGkuDQoNCmBgYHtyfQ0KKHAxIHwgcDIgfCBwMykgKyBwbG90X2xheW91dCh3aWR0aHMgPSBjKDIsIDIsIDQpKQ0KYGBgDQoNCkVlbG1pbmUgcGlsdCBqw6RpIGtvbGUgc2VzdCB2YXN0YXZhdGUgbGFpdXN0ZWdhIG9uIGdyYWFmaWt1dGUgYW5kbWVpZCBuw6RpdGF2YWQgcGFuZWVsaWQuIEt1bmEga2FoZWwgZ3JhYWZpa3VsIG9uIGFnYSBsZWdlbmQsIHNpaXMgbmVuZGUgbGFpdXN0IGFydmVzc2UgZWkgdsO1ZXRhLiBLw7xsbCBhZ2Egb24gdsO1aW1hbGlrIGFyZ3VtZW5kaWdhIGd1aWRlcyBrw7Vpa2lkZWx0IHBpbHRpZGVsdCBsZWdlbmRpZCBrb2trdSBrb2d1ZGEuDQoNCmBgYHtyfQ0KKHAxIHwgcDIgfCBwMykgKyBwbG90X2xheW91dCh3aWR0aHMgPSBjKDIsIDIsIDQpLCBndWlkZXMgPSAiY29sbGVjdCIpDQpgYGANCg0KUGFrZXRpcyBwYXRjaHdvcmsgb24gdmVlbCBwYWxqdSB2w7VpbWFsdXNpIGphIHRhc3ViIHV1cmlkYSBwYWtldGkga29kdWxlaHRlIDxodHRwczovL2dpdGh1Yi5jb20vdGhvbWFzcDg1L3BhdGNod29yaz4gamEgc2VhbCB2aWlkYXR1ZCDDtXBldHVzaS4NCg0KIyMjIyDDnGxlc2FuZGVkDQoNCi0gICBQcm9vdmlnZSB0ZWtpdGFkYSBqw6RyZ25ldiBwaWx0DQoNCiFbXShpbWFnZXMvU2NyZWVuc2hvdCUyMDIwMjEtMDItMjglMjBhdCUyMDE2LjE4LjIyLnBuZykNCg0KYGBge3J9DQoocDEgLyAoIHAyIHwgcDMpKSArIHBsb3RfbGF5b3V0KHdpZHRocyA9IGMoMiwgMiwgNCksIGd1aWRlcyA9ICJjb2xsZWN0IikNCmBgYA0KDQojIyBLb2R1bmUgw7xsZXNhbm5lDQoNCi0gICBQcm9vdmkgam9vbmlzdGFkYSB2w7VpbWFsaWt1bHQgc2FybmFuZSBncmFhZmlrIGrDpHJnbmV2YWdhLiBTaWluIG9uIHJha2VuZGF0dWQgdGVydmUgaHVsayBuaXBwZSwgbWlkYSBzYWkgc2VsbGVzIGphIGVlbG1pc2VzIHByYWtzaXMgw7VwaXR1ZC4gUHVua3RpZCBrdWp1bmV2YWQgc2VsbGUgcMO1aGphbCBrdWkgcGFsanUgbmVpc3QgbmlwcGlkZXN0IG9uIHJha2VuZGF0dWQuIEt1aSDDtWlnZXQgbmlwcGkgb24gcmFrZW5kYXR1ZCwga3VpZCB0dWxlbXVzIHBvbGUgdMOkcHNlbHQgaWRlbnRuZSwgc2lpcyBwdW5rdGUgbWFoYSBlaSB2w7V0YS4gTsOkaXRla3Mga3VpIHbDpHJ2IHBvbGUgdMOkcHNlbHQgw7VpZ2UgYWdhIMO1aWdlbCBncmFhZmlrdSBvc2FsIG9uIHNlZGEgc2lpc2tpIG11dWRldHVkLg0KDQogICAgIVtdKGltYWdlcy9TY3JlZW5zaG90JTIwMjAyMi0wOS0yMCUyMGF0JTIwMjIuMzkuMTclMjAxLnBuZykNCg0KYGBge3J9DQpsaW5uYWQNCmBgYA0KDQpgYGB7cn0NCmxpYnJhcnkoZ2dwbG90MikNCmxpYnJhcnkoZHBseXIpDQpsaWJyYXJ5KHBhdGNod29yaykNCg0KDQpmaWxsX2NvbHMgPC0gYygNCiAgIkxvdyIgICAgPSAiI2Y0YTE0MiIsDQogICJNZWRpdW0iID0gImdyYXk5MCIsDQogICJIaWdoIiAgID0gIiM3YjY3YzgiDQopDQoNCm91dGxpbmVfY29scyA8LSBjKA0KICAiTG93IiAgICA9ICIjZTY1MDAwIiwNCiAgIk1lZGl1bSIgPSAiI2U2NTAwMCIsDQogICJIaWdoIiAgID0gIiNlNjUwMDAiDQopDQoNCg0KZGF0YSA8LSBsaW5uYWQgJT4lIA0KICBtdXRhdGUoDQogICAgaW5jb21lX2NsYXNzID0gZmN0X3JlY29kZShpbmNvbWVfY2xhc3MsICJIaWdoIiA9ICJWZXJ5IEhpZ2giLCAiTG93IiA9ICJWZXJ5IExvdyIpLA0KICAgIFBvdmVydHlfZmFjdG9yID0gZmN0X3JlbGV2ZWwoUG92ZXJ0eV9mYWN0b3IsICJMb3ciLCAiTWVkaXVtIiwgIkhpZ2giKSwNCiAgICBCaXJ0aF9mYWN0b3IgPSBmY3RfcmVsZXZlbChCaXJ0aF9mYWN0b3IsICJMb3ciLCAiTWVkaXVtIiwgIkhpZ2giKSANCiAgKQ0KDQpwMSA8LSBnZ3Bsb3QoZGF0YSwgYWVzKHggPSBCaXJ0aF9mYWN0b3IsIHkgPSBvdmVyNjUsIGZpbGwgPSBCaXJ0aF9mYWN0b3IpKSArIA0KICAgIGdlb21fYm94cGxvdChmaWxsID0gTkEsIGNvbG9yPSJncmF5NSIpICsNCiAgICBnZW9tX3Zpb2xpbigNCiAgICAgIGFlcyhjb2xvciA9IEJpcnRoX2ZhY3RvciksDQogICAgIGFscGhhID0gMC40LCBsaW5ld2lkdGggPSAwLA0KICAgICAgZHJhd19xdWFudGlsZXMgPSBOVUxMDQogICAgKSArDQogICAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gZmlsbF9jb2xzKSArDQogICAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IG91dGxpbmVfY29scykgKw0KICAgIGdlb21faGxpbmUoeWludGVyY2VwdCA9IDEyLjUsIGxpbmV0eXBlID0gImRvdHRlZCIpICsNCiAgICBmYWNldF93cmFwKH4gU3RhdGUsIG5jb2wgPSAzKSArIA0KICAgIHRoZW1lX2J3KGJhc2Vfc2l6ZSA9IDEzKSArDQogICAgdGhlbWUoDQogICAgICBzdHJpcC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGZpbGwgPSAiI2YyYjBjNCIsIGNvbG9yID0gImJsYWNrIiksDQogICAgICBzdHJpcC50ZXh0ID0gZWxlbWVudF90ZXh0KGZhY2UgPSAiYm9sZCIpLA0KICAgICAgcGFuZWwuZ3JpZC5tYWpvci54ID0gZWxlbWVudF9ibGFuaygpLA0KICAgICAgcGFuZWwuZ3JpZC5tYWpvci55ID0gZWxlbWVudF9ibGFuaygpLA0KICAgICAgcGFuZWwuZ3JpZC5taW5vciA9IGVsZW1lbnRfYmxhbmsoKSwNCiAgICAgIHBhbmVsLmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoZmlsbCA9ICJ3aGl0ZSIsIGNvbG9yID0gTkEpLA0KICAgICAgbGVnZW5kLnBvc2l0aW9uID0gYygxLCAtMC4xKSwgDQogICAgICBsZWdlbmQuanVzdGlmaWNhdGlvbiA9IGMoMSwgMCksDQogICAgICBsZWdlbmQua2V5ID0gZWxlbWVudF9yZWN0KCBjb2xvcj0icmVkIiksDQogICAgKSANCg0KDQoNCnAyIDwtIGdncGxvdChsaW5uYWQsIGFlcyh4ID0gZGVhdGhzLCB5ID0gYmlydGhzKSkgKw0KICBnZW9tX3BvaW50KGNvbG9yID0gIndoaXRlIiwgc2l6ZSA9IDIsKSArDQogIGdlb21fc21vb3RoKGNvbG9yID0gInJlZCIsIGxpbmV3aWR0aCA9IDEpICsNCiAgdGhlbWVfdm9pZCgpICsNCiAgdGhlbWUoDQogICAgcGFuZWwuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChmaWxsID0gImJsYWNrIiwgY29sb3IgPSAiYmxhY2siKSwNCiAgICBwYW5lbC5ncmlkLm1ham9yID0gZWxlbWVudF9saW5lKGNvbG9yID0gIndoaXRlIiwgbGluZXR5cGUgPSAiZGFzaGVkIiksDQogICAgcGFuZWwuZ3JpZC5taW5vciA9IGVsZW1lbnRfbGluZShjb2xvciA9ICJ3aGl0ZSIsIGxpbmV0eXBlID0gImRhc2hlZCIpLA0KICAgIGF4aXMudGV4dCA9IGVsZW1lbnRfdGV4dChjb2xvciA9ICJibGFjayIpLA0KICAgIGF4aXMudGl0bGUgPSBlbGVtZW50X3RleHQoY29sb3IgPSAiYmxhY2siKSwNCiAgICBwbG90LmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoZmlsbCA9ICJ3aGl0ZSIsIGNvbG9yID0gIndoaXRlIiksDQogICAgYXhpcy50aXRsZS55ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gOTApDQogICkgKw0KICAgIHNjYWxlX3hfY29udGludW91cyhuYW1lID0gIkhpZ2hlciBlZHVjYXRpb24gcGVyY2VudGFnZSIsIGJyZWFrcyA9IGMoMCwgMC41LCAxLCAxLjUsIDIpKSsNCiAgbGFicyh4ID0gImRlYXRocyIsIHkgPSAiYmlydGhzIikNCg0KDQpwMSAvIHAyICsgcGxvdF9sYXlvdXQoaGVpZ2h0cyA9IGMoMywgMSkpDQpgYGANCg0KIyMgZ2dwbG90Mi1nYSBncmFhZmlrdXRlIGpvb25pc3RhbWlzZSBoYXJqdXRhbWluZQ0KDQpTZWxsZSBqYSBlZWxtaXNlIHByYWt0aWt1bWkgcMO1aGphbCBwZWFrcyBvbHVsaXNlbWFkIG9za3VzZWQgZ2dwbG90MiBrYXN1dGFtaXNla3Mgb2xlbWFzIG9sZW1hLiBOw7zDvGQgcHJvb3ZpbWUgbmVpZCByYWtlbmRhZGEsIGthc3V0YWRlcyBrYSB0ZWFkbWlzaSB0ZWlzZXN0IGxvZW5ndXN0LCBrdXMgc2FpIHR1dHZ1c3RhdHVkIGdyYWFmaWt1dGUgdmFsaW1pc2UgcMO1aGltw7V0dGVpZCB0w6Rwc2VtYWx0Lg0KDQpMb2VtZSBzaXNzZSBrw7VpZ2VwZWFsdCBhbmRtZXN0aWt1LCBtaXMga2lyamVsZGFiIHNpaXMgMjAwMCBpbmltZXNlIGtlaGFtYXNzaSBpbmRla3NlaWQgamEganVodXNsaWt1bCBww6RldmFsIHRlaHR1ZCBzYW1tdWRlIGFydnUuIElnYSBpbmltZXNlIGtvaHRhIG9uIGthIGFudHVkIHN1Z3UsIHZhbnVzIGphIHZhbnVzZWdydXBwLiBMb2VtZSBhbmRtZXN0aWt1IHNpc3NlLg0KDQpgYGB7cn0NCmxvYWQoImJtaS5SRGF0YSIsIHZlcmJvc2UgPSBUKQ0KDQpibWkNCmBgYA0KDQpJZ2Egw7xsZXNhbmRlIHB1aHVsIHRhc3ViIHByb292aWRhIGVyaW5ldmFpZCB2YXJpYW50ZSBqYSBtw7VlbGRhIG1pbGxpbmUgdMO2w7Z0YWIgYW50dWQgb2x1a29ycmFzIHBhcmVtaW5pIGphIG1pa3MuIE1lZWxkZXR1bGV0dXNla3MsIHNpaW4gb24gb2x1bGlzZW1hZCBrw6RzdWQgbWlkYSB2YWphIHbDtWliIG1pbm5hDQoNCi0gICBgZ2VvbV9wb2ludGANCg0KLSAgIGBnZW9tX2hpc3RvZ3JhbWANCg0KLSAgIGBnZW9tX2JhcmANCg0KLSAgIGBnZW9tX2JveHBsb3RgDQoNCi0gICBgZ2VvbV9kZW5zaXR5YA0KDQotICAgYGdlb21fdmlvbGluYA0KDQotICAgYGdlb21fc21vb3RoYA0KDQotICAgYGZhY2V0X2dyaWRgDQoNCiMjIyMgw5xsZXNhbmRlZA0KDQotICAgMSBNaWxsaW5lIHRlaHR1ZCBzYW1tdWRlIGphb3R1cz8gTWlsbGlzdCBnZW9tZWV0cmlsaXN0IGVzaXR1c3QgdsO1aWIgc2VsbGUgdXVyaW1pc2VrcyBrYXN1dGFkYT8NCg0KLSAgIDIgTWlsbGluZSBvbiB0ZWh0dWQgc2FtbXVkZSBqYW90dXMgc3VndWRlIGthdXBhPyBWaWhqZWQ6DQoNCiAgICAtICAgZXQgam9vbmlzdGFkYSBoaXN0b2dyYW1taWQgw7xrc3RlaXNlIHBlYWxlIHRhc3ViIHBhbm5hIGBwb3NpdGlvbiA9ICJpZGVudGl0eSJgDQoNCiAgICAtICAgYXJndW1lbnQgYGFscGhhYCBrb250cm9sbGliIHbDpHJ2aWRlIGzDpGJpcGFpc3R2dXN0DQoNCi0gICAzIEt1bW1hIHNvbyBlc2luZGFqYWQgdGVldmFkIG1lZGlhYW5pcyB2w6RoZW0gc2FtbXVzaWQ/DQoNCi0gICA0IFRlZSBsw6RiaSBzZWUgc2FtYSB2w7VyZGx1cyB2YW51c2VncnVwcGlkZSBrYXVwYS4gS2FzIGrDpHJlbGR1cyBvbiBzYW1hPw0KDQotICAgNSBWYWF0YSB2YW51c2VncnVwcGlkZSBhcnZ1a3VzdCBzdWd1ZGUga2F1cGEuIEthcyBqYW90dXMgb24gc2FybmFuZSB2w7VpIGVyaW5ldj8NCg0KLSAgIDYgS2FzIHZhbnVzZSBqYSB0ZWh0dWQgc2FtbXVkZSB2YWhlbCBvbiBzZW9zPyBLYXMgc2VvcyB0dW5kdWIgbGluZWFhcm5lPw0KDQotICAgNyBNaWxsaW5lIG9uIHNlb3Mga2VoYW1hc3NpIGluZGVrc2kgamEgc2FtbXVkZSB2YWhlbD8gS2FzIHNlb3Mgb24gbGluZWFhcm5lIGphIHbDtWkgb24gdGVndSBtaWxsZWdpIGtlZXJ1a2FtYWdhPw0KDQpgYGB7cn0NCg0KIzENCmdncGxvdChibWksIGFlcyh4ID0gU3RlcHMpKSArDQogIGdlb21faGlzdG9ncmFtKCkNCg0KZ2dwbG90KGJtaSwgYWVzKHggPSBTdGVwcykpICsNCiAgZ2VvbV9oaXN0b2dyYW0oYmlucyA9IDEwMCkNCg0KZ2dwbG90KGJtaSwgYWVzKHggPSBTdGVwcykpICsNCiAgZ2VvbV9kZW5zaXR5KCkNCg0KZ2dwbG90KGJtaSwgYWVzKHggPSBTdGVwcykpICsNCiAgZ2VvbV9ib3hwbG90KCkNCmBgYA0KDQpgYGB7cn0NCg0KIzINCmdncGxvdChibWksIGFlcyh4ID0gU3RlcHMsIGZpbGw9R2VuZGVyKSkgKw0KICAgIGdlb21faGlzdG9ncmFtKHBvc2l0aW9uID0gImlkZW50aXR5IiwgYWxwaGE9MC4zKQ0KDQpnZ3Bsb3QoYm1pLCBhZXMoeCA9IFN0ZXBzLCBmaWxsPUdlbmRlciwgY29sb3I9R2VuZGVyKSkgKw0KICAgIGdlb21faGlzdG9ncmFtKHBvc2l0aW9uID0gImlkZW50aXR5IiwgYWxwaGE9MC4zKQ0KDQoNCmdncGxvdChibWksIGFlcyh4ID0gU3RlcHMsIGZpbGw9R2VuZGVyLCBjb2xvcj1HZW5kZXIpKSArDQogIGdlb21fZGVuc2l0eShwb3NpdGlvbiA9ICJpZGVudGl0eSIsIGFscGhhPTAuMykNCg0KYGBgDQoNCmBgYHtyfQ0KDQojMw0KDQpnZ3Bsb3QoYm1pLCBhZXMoeCA9IFN0ZXBzLCB5PUdlbmRlcikpICsNCiAgZ2VvbV9ib3hwbG90KCkNCg0KYGBgDQoNCmBgYHtyfQ0KDQojNA0KZ2dwbG90KGJtaSwgYWVzKHggPSBTdGVwcywgeT1BZ2VHcm91cCwgZmlsbD1HZW5kZXIpKSArDQogIGdlb21fYm94cGxvdCgpDQpgYGANCg0KYGBge3J9DQoNCiM1DQpnZ3Bsb3QoYm1pLCBhZXMoeCA9IEdlbmRlciwgZmlsbD1BZ2VHcm91cCkpICsNCiAgZ2VvbV9iYXIoKQ0KDQpnZ3Bsb3QoYm1pLCBhZXMoeCA9IEdlbmRlciwgZmlsbD1BZ2VHcm91cCkpICsNCiAgZ2VvbV9iYXIocG9zaXRpb249ImRvZGdlIikNCg0KZ2dwbG90KGJtaSwgYWVzKHggPSBHZW5kZXIsIGZpbGw9QWdlR3JvdXApKSArDQogIGdlb21fYmFyKHBvc2l0aW9uPSJmaWxsIikNCmBgYA0KDQpgYGB7cn0NCg0KIzYNCmdncGxvdChibWksIGFlcyh4ID0gQWdlLCB5PVN0ZXBzKSkgKw0KICBnZW9tX3BvaW50KCkgKw0KICBnZW9tX3Ntb290aCgpDQoNCmdncGxvdChibWksIGFlcyh4ID0gQWdlLCB5PVN0ZXBzKSkgKw0KICBnZW9tX3BvaW50KCkgKw0KICBnZW9tX3Ntb290aChtZXRob2QgPSAibG0iKQ0KYGBgDQoNCmBgYHtyfQ0KDQojNyANCmdncGxvdChibWksIGFlcyh4ID0gQk1JLCB5PVN0ZXBzKSkgKw0KICBnZW9tX3BvaW50KCkgKw0KICBnZW9tX3Ntb290aCgpDQoNCmdncGxvdChibWksIGFlcyh5ID0gQk1JLCB4PVN0ZXBzKSkgKw0KICBnZW9tX3BvaW50KCkgKw0KICBnZW9tX3Ntb290aChtZXRob2QgPSAibG0iKQ0KYGBgDQoNCiMjIEtvZHVuZSDDvGxlc2FubmUNCg0KRmFpbGlzIGB5bGV2YWF0dXNlZC5SRGF0YWAgb24gYW5kbWVzdGlrIGvDtWlnaSBFZXN0aXMgdG9pbWUgcGFuZHVkIHPDtWlkdWtpdGUgdGVobmlsaXN0ZSDDvGxldmFhdHVzdGUga29odGEuIFR1bm51c3RlIGtvaHRhIGxpc2FpbmZvdCBwYWxqdSBwb2xlLCBrdWlkIG5pbWVkIHBlYWtzIHN1aHQgc2VsZ2VkIG9sZW1hLiBBbmRtZXN0aWsgcMOkcmluZWIgZWVzdGkgYXZhYW5kbWV0ZSBwb3J0YWFsaXN0OiA8aHR0cHM6Ly9hdmFhbmRtZWQuZWVzdGkuZWUvZGF0YXNldHMvbWFpc21hYXNvaWR1a2l0ZS10ZWhub3VsZXZhYXR1c2VkLWVlc3Rpcz4NCg0Kw5xsZXNhbmRla3Mgb24gc2VsbGUgYW5kbWVzdGlrdSBww7VoamFsIGpvb25pc3RhZGEgdsOkbGphIGdyYWFmaWsgbWlzIHRvb2IgdsOkbGphIG1pbmdpIGh1dml0YXZhIHNlb3NlLiBBbmRtZXN0aWsgb24gc3V1ciBqYSBncmFhZmlrIGVpIHBlYSBrYWphc3RhbWEgdGVydmV0IGFuZG1lc3Rpa2t1LCB2YWlkIHbDtWliIGtlc2tlbmR1ZGEgbWluZ2lsZSBhbmRtZXRlIGFsYW1odWxnYWxlLg0KDQpTZWxsZWwgZ3JhYWZpa3VsIHbDtWliIG9sbGEgbWl0dSBwYW5lZWxpLCBrdWlkIHBlYWIgb2xlbWEgc2lpc2tpICoqw7xrcyoqIGZhaWwsIG1pcyB2w6RsamEgdHLDvGtraWRlcyBtYWh1a3Mgw7xoZWxlIGxlaGVsZSBqYSBvbGVrcyBsb2V0YXYuIEt1bmEgYW5kbWVkIG9uIGtlZXJ1a2FkIHbDtWliIHBpbGRpIHNhbHZlc3RhZGEgc3V1cmVtYW5hLCBrdWkgUnN0dWRpbyBncmFhZmlrdSBha25hc3NlIG1haHViIChrYXN1dGFkZXMga8Okc2t1IGBnZ3NhdmVgIGphIGFyZ3VtZW50ZSBgaGVpZ2h0YCBqYSBgd2lkdGhgKSwgZXQga8O1aWdlbCB2YWphbGlrdWwgcGlpc2F2YWx0IHJ1dW1pIG9sZWtzLg0KDQpFc2l0YWRhIHR1bGViIGdyYWFmaWt1dCBnZW5lcmVlcml2ICoqa29vZCoqLCBww7VoamVuZHVzIG1pa3MganVzdCBhbnR1ZCB0w7zDvHBpIGdyYWFmaWsodWQpIG9uIG5lbmRlIGFuZG1ldGUgbsOkaXRhbWlzZWtzIGhlYSBqYSBrYSBtw7VuZSBsYXVzZWxpbmUgKipqw6RyZWxkdXMqKiwgbWlsbGUgdGUgcGlsZGlsdCBvbGV0ZSB2w6RsamEgbHVnZW51ZC4NCg0KR3JhYWZpayBwZWFiIHZhc3RhbWEgasOkcmduZXZhdGVsZSB0aW5naW11c3RlbGUuDQoNCi0gICBLYXN1dGF0dWQgb24gdsOkaGVtYWx0IDUgZXJpbmV2YXQgdHVubnVzdA0KDQotICAgS2FzdXRhdHVkIG9uIHbDpGhlbWFsdCAyIGVyaW5ldmF0IGdlb21cX1wqIGZ1bmt0c2lvb25pDQoNCi0gICBPbiBtb2RpZml0c2Vlcml0dWQgZ3JhYWZpa3UgZWxlbWVudGlkZSB2w6RsamFuw6RnZW1pc3QgbmluZyBuZWVkIG11dWRhdHVzZWQgb24gYXNqYWtvaGFzZWQNCg0KLSAgIE9uIHZhbGl0dWQgYW5kbWV0ZWxlIHNvYml2IHZpc3VhbGlzZWVyaW1pc2UgbWVldG9kDQoNCi0gICBHcmFhZmlrIGVpIHZhamEgbGlzYXNlbGdpdHVzaSBuaW5nIG9uIGtlcmdlc3RpIGxvZXRhdiAoa8O1aWsgdGVrc3RpZCBzdXVydGUgYWxndXN0w6RodGVkZWdhLCBncmFtbWF0aWxpc2VsdCBrb3JyZWt0c2VkLCBwaWlzYXZhbHQga2lyamVsZGF2YWQpLg0KDQotICAgVGVrc3RpbGlzZWQgasOkcmVsZHVzZWQgamEgZ3JhYWZpayBsw6RoZXZhZCBrb2trdS4NCg0KYGBge3J9DQoNCmxvYWQoInlsZXZhYXR1c2VkLlJEYXRhIiwgdmVyYm9zZSA9IFQpDQoNCnlsZXZhYXR1c2VkDQpgYGANCg0KYGBge3J9DQpuYW1lcyh5bGV2YWF0dXNlZCkgIyBjb2xuYW1lcyh5bGV2YWF0dXNlZCkNCg0KDQp1bmlxdWUoeWxldmFhdHVzZWQkWUxFVkFBVFVTT1RTVVMpDQoNCg0Kc3RyKHlsZXZhYXR1c2VkKQ0KYGBgDQoNCmBgYHtyfQ0KbGlicmFyeSh0aWR5dmVyc2UpDQpsaWJyYXJ5KHBhdGNod29yaykNCmBgYA0KDQpgYGB7cn0NCnlsZXYgPC0geWxldmFhdHVzZWQgJT4lDQogIG11dGF0ZSgNCiAgICBSSUtLRUQgPSBpZmVsc2UoaXMubmEoUklLS0VEKSwgIiIsIFJJS0tFRCksDQogICAgVklHQURFX0FSViA9IGlmZWxzZShSSUtLRUQgPT0gIiIsIDAsIHN0cl9jb3VudChSSUtLRUQsICI7IikgKyAxKSwNCiAgKSAlPiUNCiAgZmlsdGVyKHN0cl9zdGFydHMoS0FURUdPT1JJQSwgIk0iKSAmICFpcy5uYShLQVRFR09PUklBKSkgJT4lDQogbXV0YXRlKEtFUkVUWVlQX0dSVVBQID0gY2FzZV93aGVuKA0KICAgIEtFUkVUWVlQICVpbiUgYygiTUFIVFVOSVZFUlNBQUwiLCAiVU5JVkVSU0FBTCIsICJMVVVLUMOEUkEiLCAiU0VEQUFOIiwNCiAgICAgICAgICAgICAgICAgICAgIktVUEVFIiwgIkxJTVVTSUlOIiwgIktPTUJJIikgfiAiU8O1aWR1YXV0byIsDQoNCiAgICBLRVJFVFlZUCAlaW4lIGMoIkxBSFRJTkUiLCAiUElLQVAiLCANCiAgICAgICAgICAgICAgICAgICAgIlNJSFRPVFNUQVJCRUxJTkUiLCAiRVJJT1RTVEFSQkVMSU5FIFPDlUlEVUsiKSB+ICJLYXViaWsgLyB0w7bDtmF1dG8iLA0KDQogICAgS0VSRVRZWVAgJWluJSBjKCJNSVRNRU9UU1RBUkJFTElORSBTw5VJRFVLIikgfiAiTWl0bWVvdHN0YXJiZWxpbmUiLA0KDQogICAgS0VSRVRZWVAgJWluJSBjKCJCVVNTIiwgIkxJSUdFTkRCVVNTIiwgIktPUlJVU0JVU1MiLCAiVFJPTEwiKSB+ICJCdXNzIiwNCg0KICAgIEtFUkVUWVlQICVpbiUgYygiS0lJUkFCSSIsICJNQVRVU0VBVVRPIiwgIkVMQU1VIikgfiAiRXJpc8O1aWR1ayIsDQoNCiAgICBUUlVFIH4gTkENCiAgKSkNCiAgI3NhbXBsZV9uKDIwMDAwKQ0KDQp5bGV2DQpgYGANCg0KYGBge3J9DQojdW5pcXVlKHlsZXYkWUxFVkFBVFVTT1RTVVMpDQoNCnVuaXF1ZSh5bGV2JEtFUkVUWVlQKQ0KYGBgDQoNCmBgYHtyfQ0KIyBWYW51cyB2cyBtaXR0ZV9wb3NpdGlpdm5lIMO8bGV2YWF0dXNvdHN1cyAoTTEgamEgbTFnIGthdGVnb29yaWEgKHPDtWlkdXVhdG9kIGphIGJ1c3NpZCkpDQoNCmxpYnJhcnkoc2NhbGVzKQ0KcGFsZXR0ID0gaHVlX3BhbCgpKDgpDQoNCmthdGVnb29yaWFfdsOkcnZpZCA9IGMoDQogICJNMSIgICAgID0gcGFsZXR0WzJdLA0KICAiTTFHIiAgICA9IHBhbGV0dFs0XSwNCiAgIk0yIiAgICAgPSBwYWxldHRbNl0sDQogICJNMyIgICAgID0gcGFsZXR0WzhdDQopDQoNCg0KbTFfbTFnIDwtIHlsZXYgJT4lDQogIGZpbHRlcighaXMubmEoRVNNQU5FX1JFR19BQVNUQSksICFpcy5uYShZTEVWQUFUVVNPVFNVUykpICU+JQ0KICBmaWx0ZXIoWUxFVkFBVFVTT1RTVVMgJWluJSBjKCJFSV9WQVNUQV9OT1VFVEVMRSIsICJTT0lUTUlTRUtTX0tPTEJNQVRVIikpICU+JQ0KICBmaWx0ZXIoS0FURUdPT1JJQSAlaW4lIGMoIk0xIiwgIk0xRyIpKSAlPiUNCiAgZ2dwbG90KGFlcyh4ID0gRVNNQU5FX1JFR19BQVNUQSwgY29sb3IgPSBLQVRFR09PUklBLCBmaWxsID0gS0FURUdPT1JJQSkpICsNCiAgZ2VvbV9kZW5zaXR5KGFscGhhID0gMC4yKSArDQogIGxhYnMoDQogICAgdGl0bGUgPSAiU8O1aWR1YXV0b2QiLA0KICAgIHggPSAiRXNtYW5lIHJlZ2lzdHJlZXJpbXNlIGFhc3RhIiwNCiAgICB5ID0gIlRpaGVkdXMiLA0KICAgIGZpbGwgPSAiS2F0ZWdvb3JpYSIsDQogICAgY29sb3IgPSAiS2F0ZWdvb3JpYSINCiAgKSArDQogIHRoZW1lX21pbmltYWwoYmFzZV9zaXplID0gMTIpICsNCiAgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChmYWNlID0gInBsYWluIiwgc2l6ZSA9IDEyKSkgKw0KICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0ga2F0ZWdvb3JpYV92w6RydmlkKSArDQogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGthdGVnb29yaWFfdsOkcnZpZCkgDQoNCm0yX20zIDwtIHlsZXYgJT4lDQogIGZpbHRlcighaXMubmEoRVNNQU5FX1JFR19BQVNUQSksICFpcy5uYShZTEVWQUFUVVNPVFNVUykpICU+JQ0KICBmaWx0ZXIoWUxFVkFBVFVTT1RTVVMgJWluJSBjKCJFSV9WQVNUQV9OT1VFVEVMRSIsICJTT0lUTUlTRUtTX0tPTEJNQVRVIikpICU+JQ0KICBmaWx0ZXIoS0FURUdPT1JJQSAlaW4lIGMoIk0yIiwgIk0zIikpICU+JQ0KICBnZ3Bsb3QoYWVzKHggPSBFU01BTkVfUkVHX0FBU1RBLCBjb2xvciA9IEtBVEVHT09SSUEsIGZpbGwgPSBLQVRFR09PUklBKSkgKw0KICBnZW9tX2RlbnNpdHkoYWxwaGEgPSAwLjIpICsNCiAgbGFicygNCiAgICB0aXRsZSA9ICJCdXNzaWQiLA0KICAgIHggPSAiRXNtYW5lIHJlZ2lzdHJlZXJpbXNlIGFhc3RhIiwNCiAgICB5ID0gIlRpaGVkdXMiLA0KICAgIGZpbGwgPSAiS2F0ZWdvb3JpYSIsDQogICAgY29sb3IgPSAiS2F0ZWdvb3JpYSINCiAgKSArDQogIHRoZW1lX21pbmltYWwoYmFzZV9zaXplID0gMTIpICsNCiAgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChmYWNlID0gInBsYWluIiwgc2l6ZSA9IDEyKSkgKw0KICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0ga2F0ZWdvb3JpYV92w6RydmlkKSArDQogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGthdGVnb29yaWFfdsOkcnZpZCkgDQoNCg0KZ3JhYWZpazEgPC0gbTFfbTFnIC8gbTJfbTMgKw0KICAgcGxvdF9sYXlvdXQoZ3VpZGVzID0gImNvbGxlY3QiKSArDQogICBwbG90X2Fubm90YXRpb24oDQogICAgdGl0bGUgPSAiTmVnYXRpaXZuZSDDvGxldmFhdHVzb3RzdXMiLA0KICAgIHN1YnRpdGxlID0gIk0ta2F0ZWdvb3JpYSBzw7VpZHVraWQiLA0KICAgICNjYXB0aW9uID0gIkFsbGlrYXM6ID8/IHRydXN0IG1lIGJybyIsDQogICAgdGhlbWUgPSB0aGVtZSgNCiAgICAgIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoZmFjZSA9ICJib2xkIiwgc2l6ZSA9IDE2KSwNCiAgICAgIHBsb3Quc3VidGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEyKQ0KICAgICkNCiAgKSANCg0KI2dyYWFmaWsxDQpgYGANCg0KYGBge3J9DQoNCg0KIyBBdXRvIGthdGVnb29yaWEgamEgdmlnYWRlIGFydg0KZ3JhYWZpazIgPC0geWxldiAlPiUNCiAgZmlsdGVyKCFpcy5uYShLQVRFR09PUklBKSwgIWlzLm5hKEtFUkVUWVlQX0dSVVBQKSkgJT4lDQogIGdyb3VwX2J5KEtBVEVHT09SSUEpICU+JQ0KICBnZ3Bsb3QoYWVzKHkgPSBLQVRFR09PUklBLCB4ID0gVklHQURFX0FSViwgY29sb3I9S0VSRVRZWVBfR1JVUFApKSArDQogIGdlb21fcG9pbnQocG9zaXRpb24gPSAiaml0dGVyIikgKw0KICBsYWJzKA0KICAgIHRpdGxlID0gIlZpZ2FkZSBhcnYga2VyZXTDvMO8Ymkga29odGEiLA0KICAgIHN1YnRpdGxlID0gIk0ta2F0ZWdvb3JpYSBzw7VpZHVraWQiLA0KICAgIHkgPSAiS2VyZXTDvMO8cCIsDQogICAgeCA9ICJWaWdhZGUgQXJ2IiwNCiAgICBjb2xvciA9ICJLZXJldMO8w7xwIg0KICApICsNCiAgdGhlbWVfbWluaW1hbChiYXNlX3NpemUgPSAxMikgKyANCiAgIHRoZW1lKA0KICAgICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChmYWNlID0gImJvbGQiLCBzaXplID0gMTYpLA0KICAgICAgcGxvdC5zdWJ0aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTIpDQogICAgKQ0KDQojZ3JhYWZpazINCmBgYA0KDQpgYGB7ciwgZmlnLndpZHRoPTEyLCBmaWcuaGVpZ2h0PTE2fQ0KDQpncmFhZmlrMSAvIGdyYWFmaWsyICsNCiAgIHBsb3RfbGF5b3V0KGd1aWRlcyA9ICJrZWVwIikNCmBgYA0KDQoqKk1hIHRhaHRzaW4gdXVyaWRhIGrDpHJnbmV2YXQ6KioNCg0KMSkgTWlkYSB2YW5lbSBhdXRvIHNlZGEgc3V1cmVtYSB0w7VlbsOkb3N1c2VnYSBrdWt1YiDDvGxldmFhdHVzZWwgYXV0byBsw6RiaS4NCg0KMikgU8O1aWR1YXV0b2RlbCBvbiB0YXZhbGlzZWx0IHJvaGtlbSB2aWd1IGt1aSBidXNzaWRlbCwga3VuYSBhdXRvc2lkIG9uIHJvaGtlbSB0ZWVkZWwga3VpIGJ1c3NlLg0KDQoqKkrDpHJlbGR1c2VkOioqDQoNCjEpIHPDtWlkdWF1dG9kOiBNaWRhIHZhbmVtIGF1dG8sIHNlZGEgc3V1cmVtIG9uIHTDtWVuw6Rvc3VzIMO8bGV2YWF0dXNlbCBsw6RiaSBrdWtrdWRhLiBcDQpCdXNzaWQ6IFZhbnVzIGVpIHNlbGdpdGEgb3RzZXNsZXQgbMOkYmlrdWtrdW1pc3QuIEJ1c3NpZGUgcHVodWwgbcO1anV0YWIgdHVsZW11c3QgcGlnZW0gYXN1dHVzaW50ZW5zaWl2c3VzIChzdXVyZW0gYWFzdGFuZSBsw6RiaXPDtWl0KSwgbWlzdMO1dHR1IHbDtWl2YWQga2EgdXVlbWFkIGJ1c3NpZCBzYWdlZGFtaW5pIGzDpGJpIGt1a2t1ZGEuDQoNCjIpIFPDtWlkdWF1dG9kZWwgb24gcm9oa2VtIMOkw6RybXVzbGlra2UgdmlnYWRlIHbDpMOkcnR1c2ksIGt1bmEgc8O1aWR1YXV0b3NpZCBvbiB2YWxpbWlzIHR1bmR1dmFsdCByb2hrZW0ga3VpIGJ1c3NlLiBWYWxpbWkgc3V1cnVzIHRla2l0YWIgbG9vbXVsaWt1bHQgc3V1cmVtYSBoYWp1dnVzZS4NCg==